package net.alche.fa.core.doing;

import java.lang.Override;
import net.alche.fa.core.model.Logic;
import net.alche.fa.core.model.FaValue;
import net.alche.fa.core.CodeLevel;
import net.alche.fa.core.SageStone;
import net.alche.fa.core.FaException;
import java.util.List;
import java.lang.reflect.Array;
import java.util.Set;

//
// for
//
@FaAnnoDoing
@SuppressWarnings("all") 
public class ForDo extends AbstractDoing {
  static final int Max_Times = 10000000;

  @Override
  public boolean matched(String what, Logic g) {
    return "for".equals(what) || "while".equals(what) || "continue".equals(what) || "break".equals(what);
  }

  @Override
  public FaValue doing(Logic g, CodeLevel lvl, SageStone st) throws FaException {
    if ( g.getWhat().equals("continue")) {
      lvl.isContinue = true;
      return null;
    }
    if ( g.getWhat().equals("break")) {
      lvl.isBreak = true;
      return null;
    }
    if ( g.getWhat().equals("for")) {
      if ( g.getEq().equals(":")) {
        FaValue itemv = st.runCodeValue(g.getParam().get(0), lvl);
        FaValue listVal = super.getLogicValue(st, lvl, g.getParam().get(1));
        FaValue reb = forEach(listVal, itemv, g, st, lvl);
        if ( reb != null) {
          lvl.returnObj = reb;
          lvl.isReturn = true;
          return lvl.returnObj;
        }
      }
      else if ( g.getEq().equals(";")) {
        Logic firstPart = g.getParam().get(0);
        Logic sendPart = g.getParam().get(1);
        Logic thirdPart = g.getParam().get(2);
        st.runCode(firstPart, lvl);
        int max = 0;
        while ( max < Max_Times) {
          max++;
          FaValue fav = st.runCodeValue(sendPart, lvl);
          if ( fav == null || fav.getBoolValue() == null || !fav.getBoolValue()) {
            break;
          }
          CodeLevel cl = lvl.instanceDeep();
          st.runCode(g.getChild(), cl);
          if ( cl.isBreak) {
            break;
          }
          else if ( cl.isReturn) {
            lvl.returnObj = cl.returnObj;
            lvl.isReturn = true;
            return lvl.returnObj;
          }
          st.runCode(thirdPart, lvl);
        }
        if ( max >= Max_Times) {
          throw new FaException(FaException.FOR_OVER_TIMES, "超过最大数遍历");
        }
      }
    }
    else if ( g.getWhat().equals("while")) {
      Logic whileIf = g.getLogicObj();
      int max = 0;
      while ( max < Max_Times) {
        max++;
        FaValue fav = st.runCodeValue(whileIf, lvl);
        if ( fav == null || fav.getBoolValue() == null || !fav.getBoolValue()) {
          break;
        }
        CodeLevel cl = lvl.instanceDeep();
        st.runCode(g.getChild(), cl);
        if ( cl.isBreak) {
          break;
        }
        else if ( cl.isReturn) {
          lvl.returnObj = cl.returnObj;
          lvl.isReturn = true;
          return lvl.returnObj;
        }
      }
      if ( max >= Max_Times) {
        throw new FaException(FaException.FOR_OVER_TIMES, "超过最大数遍历");
      }
    }
    lvl.doChild = false;
    return null;
  }

  public FaValue forEach(FaValue listVal, FaValue itemv, Logic g, SageStone st, CodeLevel lvl) throws FaException {
    if ( listVal.getType() == FaValue._LIST) {
      if ( listVal.getObjValue() != null) {
        List list = (List)listVal.getObjValue();
        for ( Object item: list) {
          itemv.giveValue(new FaValue(item), this.plat);
          CodeLevel cl = lvl.instanceDeep();
          st.runCode(g.getChild(), cl);
          if ( cl.isBreak) {
            break;
          }
          else if ( cl.isReturn) {
            return cl.returnObj;
          }
        }
      }
    }
    else if ( listVal.getType() == FaValue._ARR) {
      Object arrObj = listVal.getValue();
      int length = Array.getLength(arrObj);
      for ( int i = 0; i < length; i++) {
        Object item = Array.get(arrObj, i);
        itemv.giveValue(new FaValue(item), this.plat);
        CodeLevel cl = lvl.instanceDeep();
        st.runCode(g.getChild(), cl);
        if ( cl.isBreak) {
          break;
        }
        else if ( cl.isReturn) {
          return cl.returnObj;
        }
      }
    }
    else if ( listVal.getType() == FaValue._OBJECT && listVal.getObjValue() != null) {
      if ( listVal.getObjValue() instanceof List) {
        List list = (List)listVal.getObjValue();
        for ( Object item: list) {
          itemv.giveValue(new FaValue(item), this.plat);
          CodeLevel cl = lvl.instanceDeep();
          st.runCode(g.getChild(), cl);
          if ( cl.isBreak) {
            break;
          }
          else if ( cl.isReturn) {
            return cl.returnObj;
          }
        }
      }
      if ( listVal.getObjValue() instanceof Set) {
        Set set = (Set)listVal.getObjValue();
        for ( Object item: set) {
          itemv.giveValue(new FaValue(item), this.plat);
          CodeLevel cl = lvl.instanceDeep();
          st.runCode(g.getChild(), cl);
          if ( cl.isBreak) {
            break;
          }
          else if ( cl.isReturn) {
            return cl.returnObj;
          }
        }
      }
    }
    return null;
  }
}